package com.example.ai.service;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.example.ai.entity.AIRequest;
import com.example.ai.entity.ProviderEnum;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jayway.jsonpath.JsonPath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.Map;

@Service
public class OpenAIService {
    /**
     * 日志
     */
    private static final Logger logger = LoggerFactory.getLogger(OpenAIService.class);

    @Value("${ai.temperature}")
    private float temperature;

    private final WebClient webClient;
    private final ObjectMapper objectMapper;

    public OpenAIService(
            @Value("${ai.api-key}") String apiKey,
            @Value("${ai.base-url}") String baseUrl,
            ObjectMapper objectMapper
    ) {
        this.webClient = WebClient.builder()
                .baseUrl(baseUrl)
                .defaultHeader("Authorization", "Bearer " + apiKey)
                .build();
        this.objectMapper = objectMapper;
    }

    @Autowired
    private ChatHistoryService chatHistoryService;

    public Mono<String> chat(AIRequest request, String provider) {
        ProviderEnum providerEnum = ProviderEnum.getInstance(provider);

        return webClient.post()
                .uri("/chat/completions")
                .bodyValue(Map.of(
                        "model", request.getModel() != null ? request.getModel() : providerEnum.getDefModel(),
                        "messages", List.of(Map.of("role", "user", "content", request.getPrompt()))
                ))
                .retrieve()
                .bodyToMono(String.class)
                .map(response -> extractAnswer(response));
    }

    private String extractAnswer(String jsonResponse) {
        // 解析JSON获取答案
        return JsonPath.read(jsonResponse, "$.choices[0].message.content");
    }

    private Map<String, Object> buildRequestBody(AIRequest request, String provider) {
        ProviderEnum providerEnum = ProviderEnum.getInstance(provider);
        Map<String, Object> model = Map.of(
                "model", request.getModel() != null ? request.getModel() : providerEnum.getDefModel(),
                "messages", List.of(Map.of("role", "user", "content", request.getPrompt())),
                "temperature", ObjectUtil.isNotEmpty(request.getTemperature()) ? request.getTemperature() : temperature,
                "stream", true
        );
        return model;
    }

    private Mono<String> parseReasoningContent(String json) {
        try {
            JsonNode node = objectMapper.readTree(json);
            logger.info("node===>:{}", node);
            return Mono.justOrEmpty(node.path("choices")
                    .path(0)
                    .path("delta")
                    .path("reasoningContent")
                    .requireNonNull()
                    .asText());
        } catch (JsonProcessingException e) {
            return Mono.error(e);
        }
    }

    private Mono<String> parseContent(String json) {
        try {
            JsonNode node = objectMapper.readTree(json);
            logger.info("node===>:{}", node);
            return Mono.justOrEmpty(node.path("choices")
                    .path(0)
                    .path("delta")
                    .path("content")
                    .requireNonNull()
                    .asText());
        } catch (JsonProcessingException e) {
            return Mono.error(e);
        }
    }

    public Flux<ServerSentEvent<String>> streamCompletion(AIRequest request, String provider, String userId) {
        StringBuilder finalContent = new StringBuilder();
        Flux<ServerSentEvent<String>> serverSentEventFlux = webClient.post()
                .uri("/chat/completions")
                .contentType(MediaType.APPLICATION_JSON)
                .bodyValue(buildRequestBody(request, provider))
                .retrieve()
                .bodyToFlux(String.class)
                .flatMap(json -> {
                    try {
                        JsonNode node = objectMapper.readTree(json);
                        logger.info("node===>:{}", node);

                        if (node == null) {
                            return Mono.empty();
                        }

                        JsonNode choices = node.get("choices");
                        if (choices == null || !choices.isArray() || choices.isEmpty()) {
                            return Mono.empty();
                        }

                        JsonNode firstChoice = choices.get(0);
                        JsonNode delta = firstChoice.get("delta");
                        if (delta == null) {
                            return Mono.empty();
                        }

                        // Check for reasoningContent
                        JsonNode reasoningNode = delta.get("reasoning_content");
                        if (reasoningNode != null && !reasoningNode.isMissingNode()) {
                            String reasoningContent = reasoningNode.asText();
                            if (StrUtil.isNotBlank(reasoningContent) && !reasoningContent.equals("null")) {
                                finalContent.append(reasoningContent);
                                return Mono.just(ServerSentEvent.builder(reasoningContent)
                                        .event("reasoning-message")
                                        .build());
                            }
                        }

                        // Check for content if reasoningContent not found
                        JsonNode contentNode = delta.get("content");
                        if (contentNode != null && !contentNode.isMissingNode()) {
                            String content = contentNode.asText();
                            if (StrUtil.isNotBlank(content) && !content.equals("null")) {
                                finalContent.append(content);
                                return Mono.just(ServerSentEvent.builder(content)
                                        .event("ai-message")
                                        .build());
                            }
                        }

                        return Mono.empty();
                    } catch (JsonProcessingException e) {
                        logger.error("JSON parsing error", e);
                        return Mono.error(e);
                    }
                }).concatWith(Flux.just(
                        ServerSentEvent.<String>builder()
                                .event("end")
                                .data("[DONE]")
                                .build()
                ));
        chatHistoryService.saveMessagePair(userId, request.getSessionId(), request.getPrompt(), finalContent.toString(), 1);
        return serverSentEventFlux;
    }
}
